#include "stdafx.h"
#include "Draw.h"
#include "Text.h"
#include "TextMetrics.h"
#include "ScrollBar.h"
#include "LetterCode.h"
#include "SegmentManager.h"
#include "WindowMetrics.h"
#include "Bookmark.h"
#include "GdiPlusEx.h"

void Draw::Invalidate()
{
}

void Draw::InvalidateScreen()
{
	InvalidateRect(hWnd, NULL, TRUE);
}

void Draw::SetSelColorOnSetFocus()
{
	SelFore = GetSysColor(COLOR_HIGHLIGHTTEXT);
	SelBack = GetSysColor(COLOR_HIGHLIGHT);
}

void Draw::SetSelColorOnKillFocus()
{
	switch(SelType)
	{
	case HIDE:
		SelFore = RGB(0, 0, 0);
		SelBack = GetSysColor(COLOR_WINDOW);
		break;
	case DIM:
		SelFore = RGB(255, 255, 255);
		SelBack = RGB(192, 192, 192);
		break;
	case SHOW:
		break;
	}
}

void Draw::DrawMargin(HDC hdc, RECT* markRect, int row)
{
	Row rowInfo;
	if(row < text->GetNumberOfRows())
	{
		rowInfo = text->GetRowInfo(row);
	}

	if(wm->IsMarkArea())
	{
		HBRUSH marBrush = CreateSolidBrush(marColor);
		FillRect(hdc, markRect, marBrush);
		
		if(row < text->GetNumberOfRows() && rowInfo.isLineStart && mark->IsBookmark(rowInfo.LineNumber))
		{
			using namespace GDIPlusEx;

			Graphics g(hdc);
			Pen p(Color(0, 0, 255));
			LinearGradientBrush b(Rect(0, 0, wm->GetMarkAreaWidth(), tm->GetFontHeight()), Color(255, 255, 255),
				Color(0, 0, 255), LinearGradientModeForwardDiagonal);
			
			FillRoundRect(&g, &b, 0, 0, wm->GetMarkAreaWidth() - 1, tm->GetFontHeight() - 1, 
				int(wm->GetMarkAreaWidth() * 0.1), int(tm->GetFontHeight() * 0.1));
			DrawRoundRect(&g, &p, 0, 0, wm->GetMarkAreaWidth() - 1, tm->GetFontHeight() - 1, 
				int(wm->GetMarkAreaWidth() * 0.1), int(tm->GetFontHeight() * 0.1));
		}
		DeleteObject(marBrush);
	}

	HBRUSH brush = GetSysColorBrush(COLOR_WINDOW);

	if(wm->IsNumArea() && row < text->GetNumberOfRows() && markRect->bottom < wm->GetWndHeight())
	{
		RECT rt = {wm->GetMarkAreaWidth(), 0, wm->GetMarkAreaWidth() + wm->GetNumAreaWidth(), 
			tm->GetLineHeight()};
		FillRect(hdc, &rt, brush);

		if(rowInfo.isLineStart)
		{
			TCHAR line[10];
			wsprintf(line, L"%d", rowInfo.LineNumber);
			UINT oldAlign = SetTextAlign(hdc, TA_RIGHT);
			UINT oldBkMode = SetBkMode(hdc, TRANSPARENT);
			SetTextColor(hdc, numColor);

			TextOut(hdc, wm->GetMarkAreaWidth() + wm->GetNumAreaWidth() - 1, 0, line, lstrlen(line));

			SetTextAlign(hdc, oldAlign);
			SetBkMode(hdc, oldBkMode);				
		}
	}

	RECT outliningRect = {wm->GetMarkAreaWidth() + wm->GetNumAreaWidth(), 0,
		wm->GetMarkAreaWidth() + wm->GetNumAreaWidth() + 10, tm->GetLineHeight()};
	FillRect(hdc, &outliningRect, brush);

	DeleteObject(brush);
}

void Draw::SetHideSelType(HideSelType type)
{
	SelType = type;
}

HideSelType Draw::GetHideSelType()
{
	return SelType;
}

void Draw::ShowTab(bool show)
{
	showTab = show;
}

void Draw::ShowSpace(bool show)
{
	showSpace = show;
}

void Draw::ShowEnter(bool show)
{
	showEnter = show;
}

void Draw::ShowNowLine(bool show)
{
	showNowLine = show;
}

void Draw::SetCtrlCodeColor(COLORREF color)
{
	ctrlCodeColor = color;
}

void Draw::SetNowLineColor(COLORREF color)
{
	nowLineColor = color;
}

bool Draw::IsShowingNowLine()
{
	return showNowLine;
}

Draw::Draw()
{
	SetSelColorOnSetFocus();

	SelType = DIM;
	marColor = RGB(236, 233, 216);
	numColor = RGB(43, 145, 175);

	showTab = showEnter = showSpace = true;
	ctrlCodeColor = numColor;

	showNowLine = true;
	nowLineColor = RGB(255, 255, 192);
}

void Draw::Init(HWND hWnd, Text* text, TextMetrics* tm, ScrollBar* scroll,
				SegmentManager* segManager, WindowMetrics* wm, Bookmark* mark)
{
	this->hWnd = hWnd;
	this->text = text;
	this->tm = tm;
	this->scroll = scroll;
	this->segManager = segManager;
	this->wm = wm;
	this->mark = mark;
}

void Draw::DrawLine(HDC hdc, int row)
{
	wstring temp = text->GetString(row);
	vector<Segment> segs = segManager->AnalyzeString(row);

	DrawBackground(hdc, text->GetRow() == row);
	int x = -scroll->GetXPos() + wm->GetMarginWidth();
	for(int i = 0; i < int(segs.size()); i++)
	{
		bool isTab = false;
		if(segs[i].isTab)
		{
			isTab = true;
		}

		COLORREF fore, back;
		if(segs[i].stat == SEL)
		{
			fore = SelFore;
			back = SelBack;
		}
		else
		{
			fore = RGB(0, 0, 0);
			if(showNowLine && text->GetRow() == row)
			{
				back = nowLineColor;
			}
			else
			{
				back = GetSysColor(COLOR_WINDOW);
			}
		}

		Row rowInfo = text->GetRowInfo(row);
		DrawSegment(hdc, &x, 0,
			temp.substr(segs[i].start, segs[i].end - segs[i].start),
			(i == segs.size() - 1 && rowInfo.isLineEnd), isTab, fore, back);
	}

	RECT rt = {0, 0, wm->GetMarkAreaWidth(), tm->GetLineHeight()};
	DrawMargin(hdc, &rt, row);
}

void Draw::DrawSegment(HDC hdc, int* x, int y, wstring& str, bool isLineEnd, bool isTab, COLORREF fore, COLORREF back)
{
	if(isTab)
	{
		int oldx = *x;
		int docx = *x + scroll->GetXPos();
		docx = tm->CalcNextDocXFromTab(docx);
		*x = docx - scroll->GetXPos();
		RECT rt = {oldx, y, *x + 1, y + tm->GetFontHeight()};
		HBRUSH brush = CreateSolidBrush(back);
		FillRect(hdc, &rt, brush);
		DeleteObject(brush);
		if(showTab) DrawTab(hdc, oldx, tm->GetFontHeight());
	}
	else
	{
		SetTextColor(hdc, fore);
		SetBkColor(hdc, back);
		TextOut(hdc, *x, y, str.c_str(), str.size());
		if(showSpace) DrawSpace(hdc, *x, tm->GetFontHeight(), str);
		if(showEnter || isLineEnd == false)
		{
			*x += tm->CalcStringLength(str);
		}
		if(isLineEnd) DrawEnter(hdc, *x, tm->GetFontHeight());
	}
}

#pragma warning(disable:4244)
void Draw::DrawTab(HDC hdc, int x, int height)
{
	HPEN pen = CreatePen(PS_SOLID, 1, ctrlCodeColor);
	HPEN oldPen = (HPEN)SelectObject(hdc, pen);
	
	MoveToEx(hdc, int(x + tm->GetFontWidthAverage() * 0.1), height / 2, NULL);
	LineTo(hdc, int(x + tm->GetFontWidthAverage() * 0.9), height / 2);
	LineTo(hdc, int(x + tm->GetFontWidthAverage() * 0.6), height * 0.75);
	MoveToEx(hdc, int(x + tm->GetFontWidthAverage() * 0.6), height * 0.25, NULL);
	LineTo(hdc, int(x + tm->GetFontWidthAverage() * 0.9), height / 2);
	
	SelectObject(hdc, oldPen);
	DeleteObject(pen);
}

void Draw::DrawSpace(HDC hdc, int x, int height, wstring& str)
{
	int nowX = x;
	int spaceWidth = tm->GetFontWidth(' ');

	for(int i = 0; i < int(str.size()); i++)
	{
		if(str[i] == ' ')
		{
			HBRUSH brush = CreateSolidBrush(ctrlCodeColor);
			HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, brush);
			Rectangle(hdc, nowX + spaceWidth * 0.3, height * 0.4,
				nowX + spaceWidth * 0.8, height * 0.6);
			SelectObject(hdc, oldBrush);
			DeleteObject(brush);
		}
		nowX += tm->GetFontWidth(str[i]);
	}
}

void Draw::DrawEnter(HDC hdc, int x, int height)
{
	int enterWidth = tm->GetFontWidth(' ');

	HPEN pen = CreatePen(PS_SOLID, 1, ctrlCodeColor);
	HPEN oldPen = (HPEN)SelectObject(hdc, pen);

	MoveToEx(hdc, int(x + enterWidth * 1.7), height * 0.2, NULL);
	LineTo(hdc, int(x + enterWidth * 1.7), height * 0.7);
	LineTo(hdc, int(x + enterWidth * 0.4), height * 0.7);
	LineTo(hdc, int(x + enterWidth * 1.1), height * 0.5);
	MoveToEx(hdc, int(x + enterWidth * 0.4), height * 0.7, NULL);
	LineTo(hdc, int(x + enterWidth * 1.1), height * 0.9);
	LineTo(hdc, int(x + enterWidth * 1.1), height * 0.5);

	SelectObject(hdc, oldPen);
	DeleteObject(pen);

}

void Draw::DrawBackground(HDC hdc, bool isNowLine)
{
	HBRUSH brush = CreateSolidBrush(isNowLine? nowLineColor : GetSysColor(COLOR_WINDOW));
	RECT lineRect = {wm->GetMarginWidth(), 0, wm->GetWndWidth(), tm->GetLineHeight()};
	FillRect(hdc, &lineRect, brush);
	DeleteObject(brush);
}